/* Copyright(C) 2006-2008 Dave Sexton  *
 * http://www.codeplex.com/aip         *
 * http://www.codeplex.com/aip/license *
 ***************************************/
using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Configuration.Provider;
using DaveSexton.Web.Controls.Resources;

namespace DaveSexton.Web.Controls
{
	/// <summary>
	/// An abstract base class for image providers.
	/// </summary>
	/// <remarks>
	/// <para>
	/// An image provider is a factory for <see cref="AutoInputProtectionImage"/> implementations, which generate randomized images 
	/// that contain randomized text.
	/// </para>
	/// <para>
	/// One built-in implementation is an abstract base class named, <see cref="PartitionedAutoInputProtectionImageProvider"/>, which 
	/// defines utility methods for creating instances of <see cref="PartitionedAutoInputProtectionImage"/>.
	/// </para>
	/// <para>
	/// Two concrete implementations of <see cref="PartitionedAutoInputProtectionImageProvider"/> are available for use when 
	/// configuring AIP: 
	/// </para>
	/// <list type="bullet">
	///		<item><see cref="LineNoiseAutoInputProtectionImageProvider"/></item>
	///		<item><see cref="ResourceAutoInputProtectionImageProvider"/></item>
	/// </list>
	/// <para>
	/// A custom image provider can be created by deriving a class from this class, directly or indirectly.
	/// </para>
	/// <para>
	/// Only one image provider may be configured as the default by specifying the <c>defaultImageProvider</c> attribute
	/// on the <c>&lt;autoInputProtection&gt;</c> configuration element in the web.config file.  The default image provider is used by 
	/// <see cref="AutoInputProtectionControl"/>.  If a default is not specified then the first provider added to the
	/// <c>&lt;imageProviders&gt;</c> collection element is used.  If no image providers are registered then 
	/// <see cref="LineNoiseAutoInputProtectionImageProvider"/> is used by default.
	/// </para>
	/// </remarks>
	/// <include file='examples.xml' path='//example[@id="ImageProvider"][@type="images"]'/>
	/// <include file='examples.xml' path='//example[@id="ImageProvider"][@type="config"]'/>
	/// <include file='examples.xml' path='//example[@id="ImageProvider"][@type="custom"]'/>
	/// <seealso cref="AutoInputProtection.DefaultImageProvider"/>
	/// <seealso cref="Configuration.AutoInputProtectionSection"/>
	/// <seealso cref="AutoInputProtectionTextProvider"/>
	/// <seealso cref="AutoInputProtectionFilterProvider"/>
	public abstract class AutoInputProtectionImageProvider : ProviderBase
	{
		#region Constructors
		/// <summary>
		/// Constructs a new instance of the <see cref="AutoInputProtectionImageProvider" /> class for derived classes.
		/// </summary>
		protected AutoInputProtectionImageProvider()
		{
		}
		#endregion

		#region Methods
		/// <summary>
		/// Returns a string chosen at random from the specified list of <paramref name="names"/>.
		/// </summary>
		/// <exception cref="ArgumentNullException">The value specified for <paramref name="names"/> is <see langword="null"/>.</exception>
		/// <param name="names">List of strings from which a single one will be selected at random.</param>
		/// <returns>A string chosen at random from the specified list of <paramref name="names"/>.</returns>
		public static string ChooseRandomName(IList<string> names)
		{
			if (names == null)
				throw new ArgumentNullException("names");

			return names[new Random().Next(0, names.Count)];
		}

		/// <summary>
		/// Returns a string chosen at random from the specified array of <paramref name="names"/>.
		/// </summary>
		/// <exception cref="ArgumentNullException">The value specified for <paramref name="names"/> is <see langword="null"/>.</exception>
		/// <param name="names">Array of strings from which a single one will be selected at random.</param>
		/// <returns>A string chosen at random from the specified array of <paramref name="names"/>.</returns>
		public static string ChooseRandomName(string[] names)
		{
			if (names == null)
				throw new ArgumentNullException("names");

			return names[new Random().Next(0, names.Length)];
		}

		/// <summary>
		/// When implemented by a derived type, creates an instance of a type that derives from <see cref="AutoInputProtectionImage"/>
		/// that generates an image of the specified <paramref name="size"/>, using the specified <paramref name="name"/> and 
		/// <paramref name="textProvider"/>.
		/// </summary>
		/// <remarks>
		/// Derived types are not required to use the <paramref name="name"/> argument.  This overload is not used by the 
		/// <see cref="AutoInputProtectionControl"/> control.
		/// </remarks>
		/// <seealso cref="AutoInputProtection.GenerateAutoInputProtectionImage"/>
		/// <seealso cref="GenerateRandomAutoInputProtectionImage"/>
		/// <param name="name"><see cref="String"/> that identifies a particular named resource, style or image.</param>
		/// <param name="size">The dimensions of the image.</param>
		/// <param name="textProvider"><see cref="AutoInputProtectionTextProvider"/> implementation to be used by the <see cref="AutoInputProtectionImage"/> implementation that is created.</param>
		/// <returns>An <see cref="AutoInputProtectionImage"/> implementation that can generate an image of the specified <paramref name="size"/> using the specified
		/// <paramref name="textProvider"/>.</returns>
		public abstract AutoInputProtectionImage GenerateAutoInputProtectionImage(string name, Size size, AutoInputProtectionTextProvider textProvider);

		/// <summary>
		/// When implemented by a derived type, creates an instance of a type that derives from <see cref="AutoInputProtectionImage"/>
		/// that generates an image of the specified <paramref name="size"/> using the specified <paramref name="textProvider"/>.
		/// </summary>
		/// <remarks>
		/// This overload is used by the <see cref="AutoInputProtectionControl"/> control.
		/// </remarks>
		/// <seealso cref="AutoInputProtection.GenerateAutoInputProtectionImage"/>
		/// <seealso cref="GenerateAutoInputProtectionImage"/>
		/// <param name="size">The dimensions of the image.</param>
		/// <param name="textProvider"><see cref="AutoInputProtectionTextProvider"/> implementation to be used by the <see cref="AutoInputProtectionImage"/> implementation that is created.</param>
		/// <returns>An <see cref="AutoInputProtectionImage"/> implementation that can generate an image of the specified <paramref name="size"/> using the specified
		/// <paramref name="textProvider"/>.</returns>
		public abstract AutoInputProtectionImage GenerateRandomAutoInputProtectionImage(Size size, AutoInputProtectionTextProvider textProvider);
		#endregion
	}

	/// <summary>
	/// Represents a collection of <see cref="AutoInputProtectionImageProvider"/> instances.
	/// </summary>
	/// <seealso cref="AutoInputProtection.ImageProviders"/>
	/// <seealso cref="Configuration.AutoInputProtectionSection.ImageProviders"/>
	public class AutoInputProtectionImageProviderCollection : ProviderCollection, ICollection<AutoInputProtectionImageProvider>
	{
		/// <summary>
		/// Gets the <see cref="AutoInputProtectionImageProvider"/> instance with the specified <paramref name="name"/>.
		/// </summary>
		/// <param name="name">Name of the <see cref="AutoInputProtectionImageProvider"/> instance to be retrieved.</param>
		/// <returns>The <see cref="AutoInputProtectionImageProvider"/> instance with the specified <paramref name="name"/>.</returns>
		public new AutoInputProtectionImageProvider this[string name]
		{
			get
			{
				return (AutoInputProtectionImageProvider) base[name];
			}
		}

		/// <summary>
		/// Gets the <see cref="AutoInputProtectionImageProvider"/> instance at the specified <paramref name="index"/>.
		/// </summary>
		/// <exception cref="ArgumentOutOfRangeException">The specified <paramref name="index"/> is less than zero or is 
		/// greater than or equal to the size of the collection.</exception>
		/// <param name="index">The zero-based index of the <see cref="AutoInputProtectionImageProvider"/> instance to be retrieved.</param>
		/// <returns>The <see cref="AutoInputProtectionImageProvider"/> instance at the specified <paramref name="index"/>.</returns>
		public AutoInputProtectionImageProvider this[int index]
		{
			get
			{
				int i = 0;
				foreach (AutoInputProtectionImageProvider provider in this)
				{
					if (i++ == index)
						return provider;
				}

				throw new ArgumentOutOfRangeException("index");
			}
		}

		/// <summary>
		/// Adds the specified <paramref name="provider"/> to the collection.
		/// </summary>
		/// <exception cref="ArgumentNullException">The specified <paramref name="provider"/> is <see langword="null"/>.</exception>
		/// <exception cref="ArgumentException">The specified <paramref name="provider"/> does not derive from <see cref="AutoInputProtectionImageProvider"/>.</exception>
		/// <param name="provider">An instance of a type that derives from <see cref="AutoInputProtectionImageProvider"/> to be added to the collection.</param>
		public override void Add(ProviderBase provider)
		{
			if (provider == null)
				throw new ArgumentNullException("provider");

			AutoInputProtectionImageProvider item = provider as AutoInputProtectionImageProvider;

			if (item == null)
				throw new ArgumentException(Errors.AIPImageProviderCollection_InvalidType, "provider");

			Add(item);
		}

		#region ICollection<AutoInputProtectionImageProvider> Members
		/// <summary>
		/// Adds the specified <paramref name="item"/> to the collection.
		/// </summary>
		/// <exception cref="ArgumentNullException">The specified <paramref name="item"/> is <see langword="null"/>.</exception>
		/// <param name="item">The <see cref="AutoInputProtectionImageProvider"/> instance to be added to the collection.</param>
		public void Add(AutoInputProtectionImageProvider item)
		{
			if (item == null)
				throw new ArgumentNullException("item");

			base.Add(item);
		}

		/// <summary>
		/// Returns whether the specified <paramref name="item"/> is contained by the collection.
		/// </summary>
		/// <param name="item">The <see cref="AutoInputProtectionImageProvider"/> instance to check.</param>
		/// <returns><see langword="true">True</see> if the specified <paramref name="item"/> is contained by the collection; otherwise, 
		/// <see langword="false"/>.</returns>
		public bool Contains(AutoInputProtectionImageProvider item)
		{
			if (item == null)
				return false;

			foreach (AutoInputProtectionImageProvider provider in this)
				if (provider == item)
					return true;

			return false;
		}

		/// <summary>
		/// Copies the entire collection to the specified <paramref name="array"/> starting at the specified <paramref name="arrayIndex"/>.
		/// </summary>
		/// <param name="array">An array of <see cref="AutoInputProtectionImageProvider"/> to which the collection will be copied.</param>
		/// <param name="arrayIndex">The index at which copying will begin.</param>
		public void CopyTo(AutoInputProtectionImageProvider[] array, int arrayIndex)
		{
			base.CopyTo(array, arrayIndex);
		}

		/// <summary>
		/// Gets whether the collection is read-only.
		/// </summary>
		/// <value>Indicates whether the collection is read-only.  This property always returns <see langword="false"/>.</value>
		public bool IsReadOnly
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// Removes the specified <paramref name="item"/> from the collection.
		/// </summary>
		/// <param name="item">The <see cref="AutoInputProtectionImageProvider"/> implementation to be removed.</param>
		/// <returns><see langword="true">True</see> if the specified <paramref name="item"/> is removed from the collection; otherwise, <see langword="false"/>.</returns>
		public bool Remove(AutoInputProtectionImageProvider item)
		{
			if (item == null)
				return false;

			bool contained = Contains(item);

			if (contained)
				base.Remove(item.Name);

			return contained;
		}
		#endregion

		#region IEnumerable<AutoInputProtectionImageProvider> Members
		/// <summary>
		/// Gets an object that can iterate over the entire collection of <see cref="AutoInputProtectionImageProvider"/> instances.
		/// </summary>
		/// <returns>An <see cref="IEnumerable{T}"/> of <see cref="AutoInputProtectionImageProvider"/> that can iterate over the entire collection.</returns>
		public new IEnumerator<AutoInputProtectionImageProvider> GetEnumerator()
		{
			foreach (AutoInputProtectionImageProvider provider in (System.Collections.IEnumerable) this)
				yield return provider;
		}
		#endregion
	}
}
